package com.zscat.mallplus.config;


import com.zscat.mallplus.bo.AdminUserDetails;
import com.zscat.mallplus.component.JwtAuthenticationTokenFilter;
import com.zscat.mallplus.component.RestAuthenticationEntryPoint;
import com.zscat.mallplus.component.RestfulAccessDeniedHandler;
import com.zscat.mallplus.enums.StatusEnum;
import com.zscat.mallplus.sys.entity.SysPermission;
import com.zscat.mallplus.sys.entity.SysStore;
import com.zscat.mallplus.sys.entity.SysUserVo;
import com.zscat.mallplus.sys.mapper.SysStoreMapper;
import com.zscat.mallplus.sys.mapper.SysUserMapper;
import com.zscat.mallplus.sys.service.ISysUserService;
import com.zscat.mallplus.sys.service.impl.RedisUtil;
import com.zscat.mallplus.ums.service.RedisService;
import com.zscat.mallplus.util.JsonUtil;
import com.zscat.mallplus.vo.Rediskey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import javax.annotation.Resource;
import java.util.List;


/**
 * SpringSecurity的配置
 * https://github.com/shenzhuan/mallplus on 2018/4/26.
 */
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private SysUserMapper userMapper;
    @Resource
    private SysStoreMapper storeMapper;
    @Autowired
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
    @Resource
    private RedisService redisService;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf()// 由于使用的是JWT，我们这里不需要csrf
                .disable()
                .sessionManagement()// 基于token，所以不需要session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "swagger-ui.html",
                        "/**/*.css",
                        "/**/*.js",
                        "/swagger-resources/**",
                        "/v2/api-docs/**"
                )
                .permitAll()
                .antMatchers("/admin/login", "/admin/register")// 对登录注册要允许匿名访问
                .permitAll()
                /* .and()
                 .logout()
                 .invalidateHttpSession(true)
                 .permitAll()*/
                .antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
                .permitAll()
                .antMatchers("/**")//测试时全部运行访问
                .permitAll()
                .anyRequest()// 除上面外的所有请求全部需要鉴权认证
                .authenticated();
        //访问 /logout 表示用户注销，并清空session
        httpSecurity.logout().logoutSuccessUrl("/logoutSuccess");
        // 禁用缓存
        httpSecurity.headers().cacheControl();
        // 添加JWT filter
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        httpSecurity.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthenticationEntryPoint);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    	System.out.println("11111111");
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        //获取登录用户信息
        return username -> {
            log.info("-----------------------------3232");
            SysUserVo admin = new SysUserVo();
            if (!redisService.exists(String.format(Rediskey.user, username))) {
                log.info("-----------------------------3766666666666666666666666666662");

                admin = userMapper.selectByUserName(username);
                redisService.set(String.format(Rediskey.user, username), JsonUtil.objectToJson(admin));
            } else {
                log.info("-----------------------------373333333333333333333333333662");

                admin =JsonUtil.fromJson(redisService.get(String.format(Rediskey.user, username)), SysUserVo.class);
            }
            log.info("-----------------------------377777777777777777777777777772");
            if (admin==null){
                admin = userMapper.selectByUserName(username);
                redisService.set(String.format(Rediskey.user, username), JsonUtil.objectToJson(admin));
            }
            //  apiContext.setCurrentProviderId(admin.getStoreId());
            if (admin != null) {
                if (admin.getUsername().equals("admin")) {
                    List<SysPermission> permissionList = sysUserService.listPerms();
                    return new AdminUserDetails(admin, permissionList);
                }
                if (admin.getStoreId()!=null && admin.getStoreId()>0){
                    SysStore store = storeMapper.selectById(admin.getStoreId());
                    if (store == null) {
                        throw new UsernameNotFoundException("商户不存在");
                    } else {
                        if (store.getStatus().equals(StatusEnum.AuditType.FAIL.code())) {
                            throw new UsernameNotFoundException("商户审核失败");
                        } else if (store.getStatus().equals(StatusEnum.AuditType.INIT.code())) {
                            throw new UsernameNotFoundException("商户审核中");
                        }
                    }
                }
                List<SysPermission> permissionList = sysUserService.listPerms();
//                List<SysPermission> permissionList = sysUserService.listUserPerms(admin.getId());
                return new AdminUserDetails(admin, permissionList);
            }
            throw new UsernameNotFoundException("用户名或密码错误");
        };
    }


    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

    /**
     * 允许跨域调用的过滤器
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return new CorsFilter(source);
    }
}
